using MultiAgentsShared;

namespace MultiAgentsClient.Service.WorkflowEngine.BaseNodes;

public abstract class NodeRequestToService
{
    public readonly string NodeId;

    protected NodeRequestToService(string nodeId)
    {
        NodeId = nodeId;
    }
}

public abstract class NodeResponseFromService
{
    public readonly string NodeId;

    protected NodeResponseFromService(string? nodeId)
    {
        NodeId = nodeId;
    }
}

///This node should never make its own decision, and should always rely on server
public abstract class ServiceDependentNode<TServiceRequestEvent, TServiceResponseEvent> : BaseNode
    where TServiceResponseEvent : NodeResponseFromService
    where TServiceRequestEvent : NodeRequestToService
{
    protected readonly EventBus EventBus;
    private TaskCompletionSource<NodeOutcome> _taskCompletionSource;
    private Subscription<TServiceResponseEvent> ServiceSubscription;

    protected ServiceDependentNode() : base()
    {
        EventBus = EventBus.Instance;
    }

    private void ServiceResponseHandlerInternal(TServiceResponseEvent serviceResponseEvent)
    {
        if (serviceResponseEvent.NodeId == Id)
        {
            // Process the response and determine the port index to return.
            NodeOutcome nodeOutcome = ServiceResponseHandler(serviceResponseEvent);
            _taskCompletionSource.SetResult(nodeOutcome); // Signal completion and set the port index.
        }
    }

    public override void Dispose()
    {
        ServiceSubscription.Dispose();
    }

    /// <param name="cmd"></param>
    /// <returns>a int that determines the next port to run</returns>
    protected abstract NodeOutcome ServiceResponseHandler(TServiceResponseEvent cmd);

    public sealed override async Task<NodeOutcome> ExecuteNodeAsync()
    {
        ServiceSubscription = EventBus.Subscribe<TServiceResponseEvent>(ServiceResponseHandlerInternal);

        _taskCompletionSource = new TaskCompletionSource<NodeOutcome>();
        SendRequestToService(); // Assume this method sends the request that will eventually trigger the response event.

        var receivedResult = await _taskCompletionSource.Task; // Wait here until the response handler sets the result

        Dispose();

        return receivedResult;
    }

    protected abstract void SendRequestToService();
}
